import numpy as np
import pandas as pd
from keras.models import Sequential
from keras.layers import Conv1D, LSTM, Dense, Dropout, Reshape
from keras.callbacks import EarlyStopping
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder

# 1. 数据准备与预处理
data = {
    'DATE': ['2024/1/1', '2024/1/2', '2024/1/3', '2024/1/4', '2024/1/5',
            '2024/1/6', '2024/1/7', '2024/1/8', '2024/1/9', '2024/1/10', '2024/1/11', '2024/1/12', '2024/1/13', '2024/1/14'],
    'maxTemp': [13, 9, 14, 15, 13, 12, 14, 10, 15, 16, 25, 18, 30, 14],
    'minTemp': [5, 4, 5, 5, 8, 6, 3, 5, 5, 5, -1, 10, 5, 3],
    'weather_type': ['阴天', '阴天', '晴朗', '晴朗', '雨天', '阴天', '阴天', '阴天', '晴朗', '其他', '晴朗', '阴天', '雨天', '阴天']
}

df = pd.DataFrame(data)
df['DATE'] = pd.to_datetime(df['DATE'])

# 2. 特征工程
df['day_of_year'] = df['DATE'].dt.dayofyear
df['month'] = df['DATE'].dt.month
df['day'] = df['DATE'].dt.day

weather_encoder = OneHotEncoder(sparse_output=False)
weather_encoded = weather_encoder.fit_transform(df[['weather_type']])

temp_scaler = MinMaxScaler(feature_range=(0, 1))
scaled_temps = temp_scaler.fit_transform(df[['maxTemp', 'minTemp']])

features = np.concatenate([scaled_temps, weather_encoded, df[['day_of_year', 'month', 'day']].values], axis=1)

# 3. 创建时间窗口数据集
def create_dataset(data, look_back=3, forecast_horizon=7):
    X, y = [], []
    for i in range(len(data) - look_back - forecast_horizon + 1):
        X.append(data[i:(i + look_back)])
        y.append(data[(i + look_back):(i + look_back + forecast_horizon), :2])
    return np.array(X), np.array(y)

look_back = 3
forecast_horizon = 7  # 预测未来7天
X, y = create_dataset(features, look_back, forecast_horizon)

print("X shape:", X.shape)
print("y shape:", y.shape)

if len(X) == 0 or len(y) == 0:
    raise ValueError("No samples generated. Check your look_back and forecast_horizon values.")

# 初始化模型
model = Sequential()
model.add(Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(look_back, features.shape[1])))
model.add(LSTM(units=50, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=50))
model.add(Dropout(0.2))
model.add(Dense(forecast_horizon * 2))
model.add(Reshape((forecast_horizon, 2)))

model.compile(optimizer='adam', loss='mse')

# 训练模型
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)

early_stop = EarlyStopping(monitor='val_loss', patience=50)
history = model.fit(X_train, y_train,
                   epochs=500,
                   batch_size=32,
                   validation_data=(X_test, y_test),
                   callbacks=[early_stop],
                   verbose=1)

# 预测未来7天
last_week = features[-look_back:]
last_week = last_week.reshape(1, look_back, features.shape[1])
forecast = model.predict(last_week)[0]

# 逆标准化处理
temp_forecast = forecast.reshape(forecast_horizon, 2)
temp_forecast = temp_scaler.inverse_transform(temp_forecast)

# 天气类型预测
def predict_weather(temperatures):
    avg_temp = np.mean(temperatures)
    if avg_temp > 15:
        return '晴朗'
    elif avg_temp > 10:
        return '多云'
    else:
        return '阴天'

# 生成预测结果
forecast_dates = pd.date_range(start=df['DATE'].iloc[-1] + pd.Timedelta(days=1), periods=forecast_horizon)
forecast_results = []

for i in range(forecast_horizon):
    day_forecast = {
        'date': forecast_dates[i].strftime('%Y/%m/%d'),
        'max_temp': round(temp_forecast[i][0], 1),
        'min_temp': round(temp_forecast[i][1], 1),
        'weather': predict_weather([temp_forecast[i][0], temp_forecast[i][1]])
    }
    forecast_results.append(day_forecast)

# 打印预测结果
print("\n未来7天天气预报：")
for day in forecast_results:
    print(f"{day['date']}: 最高温 {day['max_temp']}°C, 最低温 {day['min_temp']}°C, 天气 {day['weather']}")